/**
 * Copyright &copy; 2013-2015 山东易科德软件有限公司 All rights reserved.
 */
package cn.net.ecode.common.web;

import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import javax.validation.Validator;

import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.net.ecode.common.beanvalidator.BeanValidators;
import cn.net.ecode.common.utils.DateUtils;
import cn.net.ecode.common.utils.Reflections;
import cn.net.ecode.modules.sys.entity.Company;
import cn.net.ecode.modules.sys.entity.Employee;
import cn.net.ecode.modules.sys.entity.JsonEntity;
import cn.net.ecode.modules.sys.entity.User;
import cn.net.ecode.modules.sys.utils.UserUtils;

/**
 * 控制器支持类
 * @author ThinkGem
 * @version 2014-8-19
 */
public abstract class BaseController {

	/**
	 * 日志对象
	 */
	protected Logger logger = LoggerFactory.getLogger(getClass());

	/**
	 * 管理基础路径
	 */
	@Value("${adminPath}")
	protected String adminPath;
	
	/**
	 * 前端基础路径
	 */
	@Value("${frontPath}")
	protected String frontPath;
	
	/**
	 * 前端URL后缀
	 */
	@Value("${urlSuffix}")
	protected String urlSuffix;
	
	/**
	 * 验证Bean实例对象
	 */
	@Autowired
	protected Validator validator;

	/**
	 * 重定向URL前缀
	 */
	protected final static String REDIRECT = "redirect:";

	/**
	 * 转发URL前缀，不改变URL地址。
	 */
	protected final static String FORWARD = "forward:";

	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
		try{
			BeanValidators.validateWithException(validator, object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(model, list.toArray(new String[]{}));
			return false;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 flash message 中
	 */
	protected boolean beanValidator(RedirectAttributes redirectAttributes, Object object, Class<?>... groups) {
		try{
			beanValidator(object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			addMessage(redirectAttributes, list.toArray(new String[]{}));
			return false;
		}catch (ValidationException ex2) {
			if ("LAST_UPDATE_DATE_TIME".equals(ex2.getMessage())){
				addMessage(redirectAttributes, "表单已被其它用户修改");
				return false;
			}
			throw ex2;
		}
		return true;
	}
	
	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组
	 * @return 验证成功：返回true；严重失败：将错误信息添加到 message 中
	 */
	protected boolean beanValidator(StringBuilder message, Object object, Class<?>... groups) {
		try{
			beanValidator(object, groups);
		}catch(ConstraintViolationException ex){
			List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
			list.add(0, "数据验证失败：");
			message.append(StringUtils.join(list, "<br/>"));
			return false;
		}catch (ValidationException ex2) {
			if ("LAST_UPDATE_DATE_TIME".equals(ex2.getMessage())){
				message.append("表单已被其它用户修改");
				return false;
			}
			throw ex2;
		}
		return true;
	}

	/**
	 * 服务端参数有效性验证
	 * @param object 验证的实体对象
	 * @param groups 验证组，不传入此参数时，同@Valid注解验证
	 * @return 验证成功：继续执行；验证失败：抛出异常跳转400页面。
	 */
	protected void beanValidator(Object object, Class<?>... groups) {
		// 先验证最后更新时间戳
		if (!checkLastUpdateDateTime(object)){
			throw new ValidationException("LAST_UPDATE_DATE_TIME");
		}
		// 服务端参数有效性验证
		BeanValidators.validateWithException(validator, object, groups);
	}
	
	/**
	 * 乐观锁，验证最后更新时间戳，数据中的数据是否已经产生变化
	 * @param entity.lastUpdateDateTime 前台传递过来的参数
	 * @return
	 */
	protected boolean checkLastUpdateDateTime(Object entity){
		Long lastUpdateDateTime = (Long)Reflections.invokeGetter(entity, "lastUpdateDateTime");
		Long updateDateTime = (Long)Reflections.invokeGetter(entity, "updateDate.time");
		// 如果前端页面传递了最后更新时间戳
		if (lastUpdateDateTime != null && updateDateTime != null){
			if (lastUpdateDateTime.longValue() < updateDateTime.longValue()){
				return false;
			}
		}
		return true;
	}
	
	/**
	 * 添加Model消息
	 * @param message
	 */
	protected void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		model.addAttribute("message", sb.toString());
	}
	
	/**
	 * 添加Flash消息
	 * @param message
	 */
	protected void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
	}
	
	/**
	 * 客户端返回JSON字符串
	 * @param response
	 * @param object
	 * @return
	 */
	protected String renderString(HttpServletResponse response, Object object) {
		Servlets.renderString(response, object);
		return null;
	}
	
	/**
	 * 客户端返回字符串
	 * @param response
	 * @param string
	 * @return
	 */
	protected String renderString(HttpServletResponse response, String string, String type) {
		Servlets.renderString(response, string, type);
		return null;
	}

	/**
	 * 返回结果JSON字符串
	 * @param response
	 * @param result
	 * @param message
	 * @return
	 */
	protected String renderResult(String result, String message) {
		return Servlets.getRenderResult(result, message);
	}

	/**
	 * 返回结果JSON字符串
	 * @param response
	 * @param result
	 * @param message
	 * @return
	 */
	protected String renderResult(String result, StringBuilder message) {
		return Servlets.getRenderResult(result, message);
	}
	
	/**
	 * 客户端返回结果JSON字符串
	 * @param response
	 * @param result
	 * @param message
	 * @return
	 */
	protected String renderResult(HttpServletResponse response, String result, String message) {
		Servlets.renderResult(response, result, message);
		return null;
	}
	
	/**
	 * 参数绑定异常
	 */
	@ExceptionHandler({BindException.class, ConstraintViolationException.class, ValidationException.class})
    public String bindException() {  
        return "error/400";
    }
	
	/**
	 * 授权登录异常
	 */
	@ExceptionHandler({AuthenticationException.class})
    public String authenticationException() {  
        return "error/403";
    }
	
	/**
	 * 初始化数据绑定
	 * 1. 将所有传递进来的String进行HTML编码，防止XSS攻击
	 * 2. 将字段中Date类型转换为String类型
	 */
	@InitBinder
	protected void initBinder(WebDataBinder binder) {
		// 设置提交参数数组时的数组最大值，默认256个。
	    binder.setAutoGrowCollectionLimit(Integer.MAX_VALUE);
		// String类型转换，将所有传递进来的String进行HTML编码，防止XSS攻击
		binder.registerCustomEditor(String.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				if (text != null && StringUtils.startsWith(text.trim(), "<!--HTML-->")){
					setValue(text.trim());
				}else{
					setValue(text != null ? StringEscapeUtils.escapeHtml4(text.trim()) : null);
				}
			}
			@Override
			public String getAsText() {
				Object value = getValue();
				return value != null ? value.toString() : "";
			}
		});
		// Date 类型转换
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
			@Override
			public void setAsText(String text) {
				setValue(DateUtils.parseDate(text));
			}
//			@Override
//			public String getAsText() {
//				Object value = getValue();
//				return value != null ? DateUtils.formatDateTime((Date)value) : "";
//			}
		});
	}
	
	/**
	 * 解析request请求
	 * @param request
	 * @return
	 * @deprecated
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, String> parseRequest2Map(HttpServletRequest request) {
		return request.getParameterMap();
	}
	
	/**
	 * 获取分公司编码
	 * @param entity 参数实体类
	 * @return 分公司编码
	 * @deprecated
	 */
	public String getBranchCode(JsonEntity entity) {
		String branchCode = "";
		if (entity.getMapParam() == null
				|| StringUtils.isBlank(entity.getMapParam().get("branchCode"))) {
			branchCode = this.getBranchCode();
		} else {
			branchCode = entity.getMapParam().get("branchCode");
		}
		return branchCode;
	}
	
	/**
	 * 获取分公司编码
	 * @param request 参数实体类
	 * @return 分公司编码
	 * @deprecated
	 */
	public String getBranchCode(HttpServletRequest request) {
		String branchCode = "";
		if ( StringUtils.isBlank(request.getParameter("branchCode"))) {
			branchCode = this.getBranchCode();
		} else {
			branchCode = request.getParameter("branchCode");
		}
		return branchCode;
	}
	
	/**
	 * 从session中获取公司编码
	 * @return
	 * @deprecated
	 */
	public String getBranchCode() {
		String branchCode = null;
		User u = UserUtils.getUser();
		if (u == null) {
			return branchCode;
		}
		Employee e = (Employee)u.getRefObj();
		if (e == null) {
			return branchCode;
		}
		Company c = e.getCompany();
		if (c == null) {
			return branchCode;
		}
		return c.getCompanyCode();
	}
	
//	/**
//	 * 实例化entity
//	 * @param request http请求
//	 * @param t 实例的类型
//	 * @return 实例化entity
//	 */
//	@Deprecated
//	public <T> T setEntityValue(HttpServletRequest request, Class<T> t) {
//
//		// 传递的参数
//		@SuppressWarnings("unchecked")
//		Enumeration<String> param = request.getParameterNames();
//		Map<String, Object> mapParam = Maps.newHashMap();
//		while (param.hasMoreElements()) {
//			String name = param.nextElement();
//			Object value = request.getParameter(name);
//			mapParam.put(name, value);
//		}
//
//		return setEntityValue(mapParam, t);
//
//	}
//	
//	/**
//	 * 实例化entity
//	 * @param request http请求
//	 * @param t 实例的类型
//	 * @return 实例化entity
//	 */
//	@Deprecated
//	public <T> T setEntityValue(HttpServletRequest request, T t) {
//
//		// 传递的参数
//		@SuppressWarnings("unchecked")
//		Enumeration<String> param = request.getParameterNames();
//		Map<String, Object> mapParam = Maps.newHashMap();
//		while (param.hasMoreElements()) {
//			String name = param.nextElement();
//			Object value = request.getParameter(name);
//			mapParam.put(name, value);
//		}
//
//		return setEntityValue(mapParam, t);
//
//	}
//
//	/**
//	 * 实例化entity
//	 * @param mapParam Map类型的参数
//	 * @param t 实例的类型
//	 * @return 实例化entity
//	 */
//	@Deprecated
//	public  <T> T setEntityValue(Map<String, Object> mapParam, Class<T> t) {
//
//		T obj = null;
//		try {
//			obj = t.newInstance();
//		} catch (Exception e1) {
//			e1.printStackTrace();
//			return null;
//		}
//
//		return setEntityValue(mapParam, obj);
//	}
//
//	/**
//	 * 实例化entity
//	 * @param mapParam Map类型的参数
//	 * @param obj entity实例
//	 * @return 实例化entity
//	 */
//	@Deprecated
//	public  <T> T setEntityValue(Map<String, Object> mapParam, T obj) {
//
//		// 实例class的所有方法
//		Method[] methods = obj.getClass().getMethods();
//		for (Iterator<String> it = mapParam.keySet().iterator(); it.hasNext();) {
//			String name = it.next();
//			Object value = mapParam.get(name);
//
//			// 1、获取name对应的set方法，如name=nickname，则方法为setNickname
//			String methodName = "set" + name.substring(0, 1).toUpperCase()
//					+ name.substring(1);
//			// 2、获取method实例
//			for (Method method : methods) {
//				if (!method.getName().equals(methodName)) {
//					continue;
//				}
//				// 3、赋值
//				// 3.1、校验参数个数是否为1个
//				if (method.getParameterTypes() == null
//						|| method.getParameterTypes().length != 1) {
//					// 处理或提示，参数不正确
//					throw new RuntimeException("参数个数不匹配，需要"
//							+ (method.getParameterTypes() == null ? 0
//									: method.getParameterTypes().length)
//							+ ",提供了1个");
//				}
//
//				String typeName = method.getParameterTypes()[0].getName();
//				// 4、根据类型进行数据转换
//				// 5、回调，设置属性值
//				try {
//					invokeByTypeName(method, obj, typeName, value);
//				} catch (Exception e) {
//					e.printStackTrace();
//				}
//			}
//		}
//		return obj;
//	}
//
//	/**
//	 * 回调
//	 * @param obj 实例
//	 * @param typeName 参数类型，如java.lang.String
//	 * @param value 回调使用的数据
//	 * @throws Exception 回调错误
//	 */
//	@Deprecated
//	private  void invokeByTypeName(Method method, Object obj, String typeName, Object value) throws Exception {
//
//		logger.debug("typeName:" + typeName);
//
//		// 1、int类型
//		if (typeName.equals("int") || typeName.equals("java.lang.Integer")) {
//			method.invoke(obj, Integer.parseInt(String.valueOf(value)));
//			return;
//		}
//
//		// 2、float类型
//		if (typeName.equals("float") || typeName.equals("java.lang.Float")) {
//			method.invoke(obj, Float.parseFloat(String.valueOf(value)));
//			return;
//		}
//
//		// 3、long类型
//		if (typeName.equals("long") || typeName.equals("java.lang.Long")) {
//			method.invoke(obj, Long.parseLong(String.valueOf(value)));
//			return;
//		}
//
//		// 4、double类型
//		if (typeName.equals("double") || typeName.equals("java.lang.Double")) {
//			method.invoke(obj, Double.parseDouble(String.valueOf(value)));
//			return;
//		}
//
//		// 5、string类型
//		if (typeName.equals("string") || typeName.equals("java.lang.String")) {
//			method.invoke(obj, String.valueOf(value));
//			return;
//		}
//		method.invoke(obj, String.valueOf(value));
//	}
//
//	/**
//	 * 获取分页后的JSON数据，硕正专用
//	 * @param page
//	 * @Deprecated Controller中可直接返回Page对象。
//	 */
//	@Deprecated
//	protected <T> String getPageJsonString(Page<T> page)
//	{
//		List<T> list= page.getList();
//		String jsonData= JsonMapper.toJsonString(list);
//		StringBuilder resultData = new StringBuilder();
//		resultData.append("{\"totalRows\":")
//			.append(page.getCount())
//			.append(",\"Record\":")
//			.append(jsonData)
//			.append("}");
//		return resultData.toString();
//	}
	
}
